﻿/****************************************************************************************************
	Copyright (C) 2010 RapidWebDev Organization (http://rapidwebdev.org)
	Author: Eunge, Legal Name: Jian Liu, Email: eunge.liu@RapidWebDev.org

	The GNU Library General Public License (LGPL) used in RapidWebDev is 
	intended to guarantee your freedom to share and change free software - to 
	make sure the software is free for all its users.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Library General Public License (LGPL) for more details.

	You should have received a copy of the GNU Library General Public License (LGPL)
	along with this program.  
	If not, see http://www.rapidwebdev.org/Content/ByUniqueKey/OpenSourceLicense
 ****************************************************************************************************/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using RapidWebDev.Common;
using RapidWebDev.Common.Caching;
using System.Globalization;

namespace RapidWebDev.FileManagement.Thumbnails
{
    /// <summary>
	/// Api to manage thumbnails of files.
    /// </summary>
    public class ThumbnailApi : CachableApi, IThumbnailApi
    {
		private IFileManagementApi fileManagementApi;
		private IFileStorageApi fileStorageApi;
		private string thumbnailRootDirectoryPath;

        /// <summary>
        /// Sets/gets dictionary of thumbnail processors
        /// </summary>
        public Dictionary<string, IThumbnailProcessor> ThumbnailProcessors { get; set; }

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="fileManagementApi"></param>
		/// <param name="fileStorageApi"></param>
		/// <param name="thumbnailRootDirectoryPath"></param>
		public ThumbnailApi(IFileManagementApi fileManagementApi, IFileStorageApi fileStorageApi, string thumbnailRootDirectoryPath)
		{
			this.fileManagementApi = fileManagementApi;
			this.fileStorageApi = fileStorageApi;
			this.thumbnailRootDirectoryPath = Kit.ToAbsolutePath(thumbnailRootDirectoryPath);
		}

		/// <summary>
		/// Get thumbnail file head object.
		/// </summary>
		/// <param name="fileId"></param>
		/// <param name="thumbnailSize"></param>
		/// <returns>return thumbnail file head object.</returns>
		public ThumbnailFileHeadObject GetThumbnailFileHead(Guid fileId, Size thumbnailSize)
        {
			if(fileId == Guid.Empty)
				return this.ResolveDefaultThumbnail(thumbnailSize);

            ThumbnailUtilities.ValidateThumbnailSize(thumbnailSize);

			FileHeadObject fileHeadObject = this.fileManagementApi.Load(fileId);
			if (fileHeadObject == null)
                throw new ArgumentException("The file id is invalid.", "fileId");

			if (!this.ThumbnailProcessors.ContainsKey(fileHeadObject.FileExtensionName.ToLowerInvariant()))
                return this.ResolveDefaultThumbnail(thumbnailSize);

            string thumbnailFileName = string.Format("{0}x{1}.jpg", thumbnailSize.Width, thumbnailSize.Height);
			string thumbnailDirectoryPath = Path.Combine(this.thumbnailRootDirectoryPath, fileHeadObject.Id.ToString());
            if (!Directory.Exists(thumbnailDirectoryPath))
                Directory.CreateDirectory(thumbnailDirectoryPath);

            string thumbnailFilePath = Path.Combine(thumbnailDirectoryPath, thumbnailFileName);
            if (!System.IO.File.Exists(thumbnailFilePath))
            {
				Stream fileStream = this.fileStorageApi.Load(fileHeadObject);
				IThumbnailProcessor processor = this.ThumbnailProcessors[fileHeadObject.FileExtensionName.ToLowerInvariant()];
				processor.GenerateThumbnail(fileStream, thumbnailFilePath, thumbnailSize);
            }

			using (FileStream thumbnailFileStream = new FileStream(thumbnailFilePath, FileMode.Open, FileAccess.Read))
			{
				return new ThumbnailFileHeadObject
				{
					Id = fileHeadObject.Id,
					FileName = fileHeadObject.FileName,
					FileExtensionName = fileHeadObject.FileExtensionName,
					BytesCount = thumbnailFileStream.Length,
					ThumbnailFilePath = thumbnailFilePath
				};
			}
        }

		/// <summary>
		/// Delete all thumbnails of the file. 
		/// </summary>
		/// <param name="fileId"></param>
		public void DeleteThumbnails(Guid fileId)
        {
			string thumbnailDirectoryPath = Path.Combine(this.thumbnailRootDirectoryPath, fileId.ToString());
			for (int retryTime = 0; retryTime < 3; retryTime++)
			{
				try
				{
					if (Directory.Exists(thumbnailDirectoryPath))
						Directory.Delete(thumbnailDirectoryPath, true);

					break;
				}
				catch (Exception exp)
				{
					Logger.Instance(this).Warn(exp);
				}
			}
        }

		/// <summary>
		/// Resolve the thumbnail Url of the target file.
		/// </summary>
		/// <param name="fileId"></param>
		/// <param name="thumbnailWidth"></param>
		/// <param name="thumbnailHeight"></param>
		/// <returns></returns>
		public string ResolveThumbnailUrlByFileId(Guid fileId, int thumbnailWidth, int thumbnailHeight)
		{
			return string.Format(CultureInfo.InvariantCulture, "~/ThumbnailDownloadService.axd?FileId={0}&Width={1}&Height={2}", fileId, thumbnailWidth, thumbnailHeight);
		}

		/// <summary>
		/// Resolve the thumbnail Url of the target file by external object id.
		/// </summary>
		/// <param name="externalObjectId"></param>
		/// <param name="relationshipType"></param>
		/// <param name="thumbnailWidth"></param>
		/// <param name="thumbnailHeight"></param>
		/// <returns></returns>
		public string ResolveThumbnailUrlByExternalObjectId(Guid externalObjectId, string relationshipType, int thumbnailWidth, int thumbnailHeight)
		{
			return string.Format(CultureInfo.InvariantCulture, "~/ThumbnailDownloadService.axd?ExternalObjectId={0}&RelationshipType={1}&Width={2}&Height={3}", externalObjectId, relationshipType, thumbnailWidth, thumbnailHeight);
		}

		private ThumbnailFileHeadObject ResolveDefaultThumbnail(Size thumbnailSize)
        {
            string thumbnailFileName = string.Format(@"Default_{0}_{1}.jpg", thumbnailSize.Width, thumbnailSize.Height);
			string thumbnailFilePath = Path.Combine(this.thumbnailRootDirectoryPath, @"DefaultThumbnails\" + thumbnailFileName);
            if (!System.IO.File.Exists(thumbnailFilePath))
            {
				using (Stream manifestResourceStream = typeof(ThumbnailApi).Assembly.GetManifestResourceStream("RapidWebDev.FileManagement.Thumbnails.Unsupported.png"))
                {
                    ImageThumbnailProcessor processor = new ImageThumbnailProcessor();
					string directoryPath = Path.GetDirectoryName(thumbnailFilePath);
					if (!Directory.Exists(directoryPath)) Directory.CreateDirectory(directoryPath);
                    processor.GenerateThumbnail(manifestResourceStream, thumbnailFilePath, thumbnailSize);
                }
            }

			using (FileStream thumbnailFileStream = new FileStream(thumbnailFilePath, FileMode.Open, FileAccess.Read))
			{
				return new ThumbnailFileHeadObject
				{
					FileName = thumbnailFileName,
					FileExtensionName = "jpg",
					BytesCount = thumbnailFileStream.Length,
					ThumbnailFilePath = thumbnailFilePath
				};
			}
        }
    }
}